/**
 * 
 */
package com.googlecode.agiletools.backlog;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.IndexColumn;

import com.googlecode.agiletools.common.lang.time.DateIterator;
import com.googlecode.agiletools.pair.Pair;
import com.googlecode.agiletools.type.BaseObject;

/**
 * @author Administrator
 * 
 */
@Entity
@Table(name = "agiletools_sprintbacklog")
public class SprintBacklog extends BaseObject {

    private static final long serialVersionUID = -2032324972262439060L;

    public static final int DEFAULT_SPRINT_DAYS = 15;

    public static final float DEFAULT_ADJUSTMENT = 1.5f;

    private int sprintNumber;

    private String headline;

    private Date start;

    private int day = DEFAULT_SPRINT_DAYS;

    private float adjustment = DEFAULT_ADJUSTMENT;

    private List<SprintTask> tasks = new LinkedList<SprintTask>();

    private List<Float> efforts;

    /**
     * @return
     */
    private List<Float> coculateTotalLeftEffort() {
	List<Float> efforts = new LinkedList<Float>();
	float[] last = new float[tasks.size()];

	for (int day = 0; day < this.day; day++) {
	    float total = 0;
	    int taskSeq = 0;
	    for (SprintTask task : tasks) {
		Pair pair = task.getPair();
		int resource = getResourceAmount(pair);
		Float left = null;
		if (day < task.getLeftEfforts().size()) {
		    left = task.getLeftEfforts().get(day);
		}
		if (left == null) {
		    total += last[taskSeq] * resource;
		} else {
		    total += left * resource;
		    last[taskSeq] = left;
		}
		taskSeq++;
	    }
	    efforts.add(total * adjustment);
	}
	return efforts;
    }

    /**
     * @return the adjustment
     */
    public float getAdjustment() {
	return adjustment;
    }

    @Transient
    public List<Date> getDates() {
	DateIterator di = new DateIterator(start, day, true);
	List<Date> dates = new ArrayList<Date>();
	while (di.hasNext()) {
	    Date date = di.next();
	    System.out.println(date);
	    dates.add(date);
	}
	return dates;
    }

    /**
     * @return the day
     */
    public int getDay() {
	return day;
    }

    /**
     * @return the headline
     */
    @Column(length = 256)
    public String getHeadline() {
	return headline;
    }

    @Transient
    public List<Float> getLeftEfforts() {
	if (efforts == null) {
	    efforts = coculateTotalLeftEffort();
	}
	return efforts;
    }

    /**
     * @param pair
     * @return
     */
    private int getResourceAmount(Pair pair) {
	int resource = 0;
	if (pair == null) {
	    resource = 1;
	} else {
	    if ((pair.getPersonOne() != null)
		    && (!pair.getPersonOne().isEmpty())) {
		resource++;
	    }
	    if ((pair.getPersonTwo() != null)
		    && (!pair.getPersonTwo().isEmpty())) {
		resource++;
	    }
	}
	return resource;
    }

    /**
     * @return the sprintNumber
     */
    public int getSprintNumber() {
	return sprintNumber;
    }

    /**
     * @return the start
     */
    public Date getStart() {
	return start;
    }

    /**
     * @return the tasks
     */
    @Cascade( { CascadeType.ALL, CascadeType.DELETE_ORPHAN })
    @OneToMany(mappedBy = "backlog")
    @IndexColumn(name = "seq", nullable = false, base = 0)
    @JoinColumn(name = "backlogId")
    public List<SprintTask> getTasks() {
	return tasks;
    }

    public void resetLeftEfforts() {
	efforts = null;
    }

    /**
     * @param adjustment
     *            the adjustment to set
     */
    public void setAdjustment(float adjustment) {
	this.adjustment = adjustment;
    }

    /**
     * @param day
     *            the day to set
     */
    public void setDay(int day) {
	this.day = day;
    }

    /**
     * @param headline
     *            the headline to set
     */
    public void setHeadline(String headline) {
	this.headline = headline;
    }

    /**
     * @param sprintNumber
     *            the sprintNumber to set
     */
    public void setSprintNumber(int sprintNumber) {
	this.sprintNumber = sprintNumber;
    }

    /**
     * @param start
     *            the start to set
     */
    public void setStart(Date start) {
	this.start = start;
    }

    /**
     * @param tasks
     *            the tasks to set
     */
    public void setTasks(List<SprintTask> tasks) {
	this.tasks = tasks;
    }

}
